package com.obrock;

import android.database.Cursor;
import android.database.sqlite.SQLiteConstraintException;
import android.util.Log;

import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: Дмитрий Г. Кузнецов
 * Date: 01.10.12
 * Time: 16:13
 * To change this template use File | Settings | File Templates.
 */
public class SyncSeed implements Serializable, Comparable {
    public long syncID = -1;
    public String name = "";
    public long recordID = -1;
    public int operation = -1;
    public int dataLength = 0;
    public long date = 0;
    public byte[] data = new byte[]{};
    public boolean toUpdate = false;

    private static Database db = null;

    public SyncSeed(Database d, long id) throws IOException {
        db = d;

        Cursor cr = db.getReadableDatabase().rawQuery("SELECT "
                + "id, name, id_record, operation, date "
                + "FROM sync "
                + "WHERE id = ?;",
                new String[]{"" + id});
        if (cr.moveToFirst()) {
            syncID = cr.getLong(0);
            name = cr.getString(1);
            recordID = cr.getLong(2);
            operation = cr.getInt(3);
            date = cr.getLong(4);

            if (recordID != -1) {
                switch (operation) {
                    case Database.OPERATION_INSERT:
                    case Database.OPERATION_UPDATE:
                        data = db.packRecord(name, recordID);
                        if (data == null) {
                            dataLength = 0;
                        } else {
                            dataLength = data.length;
                        }
                        break;
                    case Database.OPERATION_DELETE:
                        break;
                }
            }
        }

        cr.close();
        toUpdate = false;
    }

    public SyncSeed(Database d, String table, long id) throws IOException {
        db = d;

        syncID = -1;
        name = table;
        recordID = id;
        operation = Database.OPERATION_INSERT;
        date = new Date().getTime();
        data = db.packRecord(name, recordID);
        if (data == null) {
            dataLength = 0;
        } else {
            dataLength = data.length;
        }
    }

    public SyncSeed(Database d, String query) {
        db = d;

        name = "EXECUTE";
        syncID = -1;
        recordID = -1;
        operation = Database.OPERATION_EXECUTE;
        date = new Date().getTime();
        data = query.getBytes();
        dataLength = data.length;
    }


    public SyncSeed(Database d, DataInputStream in) throws IOException {
        db = d;

        name = in.readUTF();
        syncID = in.readLong();
        recordID = in.readLong();
        operation = in.readInt();
        date = in.readLong();
        dataLength = in.readInt();
        data = new byte[dataLength];
        if (dataLength > 0) {
            in.read(data, 0, dataLength);
        }

        Cursor cr = db.getReadableDatabase().rawQuery("SELECT id FROM sync WHERE id = ?",
                new String[]{"" + syncID});
        toUpdate = !cr.moveToFirst();
        cr.close();
    }


    public void writePacket(DataOutputStream outWriter) throws IOException {

        outWriter.writeUTF(name);
        outWriter.writeLong(syncID);
        outWriter.writeLong(recordID);
        outWriter.writeInt(operation);
        outWriter.writeLong(date);
        outWriter.writeInt(dataLength);
        if (dataLength > 0) {
            outWriter.write(data);
        }
    }

    public boolean apply() throws IOException {

        if (!toUpdate) return false;
        Object[] param = new Object[0];
        String query = "";

        if (operation == Database.OPERATION_EXECUTE) {
            if (dataLength > 0) {
                query = new String(data);
            }
        } else {

            List<Record> struct = new ArrayList<Record>(0);
            if (dataLength > 0) {
                ByteArrayInputStream baStream = new ByteArrayInputStream(data);
                DataInputStream in = new DataInputStream(baStream);
                while (in.available() > 0) {
                    Record rec = new Record();
                    rec.name = in.readUTF();
                    rec.type = in.readUTF();
                    if (rec.type.equals("INTEGER")) {
                        rec.data = in.readLong();
                    } else if (rec.type.equals("REAL")) {
                        rec.data = in.readDouble();
                    } else if (rec.type.equals("TEXT")) {
                        rec.data = in.readUTF();
                    } else if (rec.type.equals("DATE")) {
                        rec.data = in.readLong();
                    }
                    struct.add(rec);
                }
            }

            String keys = "";
            String vals = "";
            param = new Object[struct.size()];

            switch (operation) {
                case Database.OPERATION_INSERT:
                    if (struct.size() > 0) {
                        for (int i = 0; i < struct.size(); ++i) {
                            if (i > 0) {
                                keys += ",";
                                vals += ",";
                            }
                            keys += struct.get(i).name;
                            vals += "?";
                            param[i] = struct.get(i).data;
                        }
                        query = "INSERT INTO " + name + "(" + keys + ") VALUES (" + vals + ");";
                    }
                    break;

                case Database.OPERATION_UPDATE:
                    if (struct.size() > 0) {
                        for (int i = 0; i < struct.size(); ++i) {
                            if (i > 0) {
                                keys += ",";
                            }
                            keys += struct.get(i).name;
                            keys += "=?";
                            param[i] = struct.get(i).data;
                        }
                        query = "UPDATE " + name + " SET " + keys + " WHERE id=" + recordID;
                    }
                    break;

                case Database.OPERATION_DELETE:
                    query = "DELETE FROM " + name + " WHERE id=" + recordID;
                    break;
            }
        }

        if (query.length() > 0) {
            try {
                Log.d(Main.LOG_TAG, "Apply: " + query);
                db.uuidEnable(false);
                db.getWritableDatabase().execSQL(query, param);
                db.uuidEnable(true);
            } catch (SQLiteConstraintException e) {
                Log.e(Main.LOG_TAG, "TABLE:" + name);
                e.printStackTrace();
                return false;
            }

        }

        return true;
    }

    @Override
    public int compareTo(Object o) {
        return (int) (syncID - ((SyncSeed) o).syncID);
    }

    class Record {
        String name = "";
        String type = "";
        int len = 0;
        Object data;
    }

}

